# Python 趣味编程：第 12 章
# 拓展练习 12.3 多个球在箱子中移动
# --------------------------
# 程序名: ex12-balls.py

import pygame
from dataclasses import dataclass, field
import random

WIDTH = 640
HEIGHT = 320

# 颜色的定义
WHITE = (255, 255, 255)
BK_COLOR = WHITE   # 背景色的设置

FPS = 60     # Frame per Second每秒帧数

@dataclass
class Ball:
    x: int
    y: int
    dx: int
    dy: int
    vx: int
    vy: int
    image: pygame.Surface

    def move(self):
        self.x += self.vx
        self.y += self.vy 

    def draw(self, to_image):
        to_image.blit(self.image, (self.x, self.y))

@dataclass
class Box:
    west: int
    north: int
    east: int
    south: int
    balls: list = field(init = False)

    def __init__(self, x, y, w, h):
        self.west, self.north = (x, y)
        self.east, self.south = (x + w, y + h)
        self.balls = []

    def check_wall(self, ball):
        if ball.x <= self.west or ball.x + ball.dx >= self.east:
            ball.vx = -ball.vx
        if ball.y <= self.north or ball.y + ball.dy >= self.south:
            ball.vy = -ball.vy

    def set_balls(self, files):
        for file in files:
            image = pygame.image.load(file).convert()   # 读取球图像
            image.set_colorkey(image.get_at((0, 0)))
            rect = image.get_rect()
            dx, dy = (rect.width, rect.height)
            # 随机数化初始位置:防止生成在墙内
            ball_x = random.randint(self.west + 1, self.east - dx - 1)
            ball_y = random.randint(self.north + 1, self.south - dy - 1)
            ball = Ball(ball_x, ball_y, dx, dy, 
                        random.randint(1, 8), random.randint(1, 8), image)
            self.balls.append(ball)

    def animate(self):
        loop = True
        screen.fill(BK_COLOR)  
        while loop: # 无限循环
            for event in pygame.event.get():
                # 处理“关闭”按钮
                if event.type == pygame.QUIT: loop = False
            clock.tick(FPS)      # 根据每秒的呼叫次数延迟
            for ball in self.balls:
                ball.move()
                self.check_wall(ball)
                ball.draw(screen)
            pygame.display.flip()   # 把绘图内容反映在画面上
            screen.fill(BK_COLOR)   

# ---------------------------------------
screen = pygame.display.set_mode((WIDTH, HEIGHT)) # 准备screen
clock = pygame.time.Clock()   # 时钟对象
draw = pygame.draw

ball_files = ["ball.png", "ball2.png", "ball2.png"]

box = Box(0, 0, WIDTH, HEIGHT) # 盘面的初始化
box.set_balls(ball_files)      # 生成球
box.animate()                  # 主程序
pygame.quit()                  # 关闭画面
